import com.itextpdf.text.DocumentException;
import integrisign.IDocInfo;
import integrisign.desktop.DeskSign;
import integrisign.desktop.ValidationException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;

/*
 * Clase que tiene la lógica para que recibiendo un pdf realice las siguientes operaciones:
 *      - Incicia el lector de ePadink para recuperar la firma del usuario.
 *      - Transforma los datos recuperados del ePadink en un XML.
 *      - Se comprime el XML en un fichero zip.
 *      - Se recupera el hash del fichero zip.
 *      - Se inserta la imagen capturada de la firma con ePadink y un código de barras con el hash del fichero 
 *          zip que contiene el XML en el documento pdf.
 *      - Se firma digitalmente el documento pdf
 * 
 * @author epindado
 */
public class FirmaPDF implements IDocInfo {
    
    private long lFecha = 0;
    private String nombreCliente = "";
    private File archivoTemporal = null;
    
    /**
     * args 0 -> ruta fichero pdf original
     * Función principal
     * @param args 
     */
    public static void main(String[] args) {
        FirmaPDF firmapdf = new FirmaPDF();
        // Incializamos el objeto que controla ePadInk
        DeskSign deskSign = new DeskSign();  
        File archivoXML = null;
        try {
            String nombrePDF = firmapdf.recuperaNombreFichero(args[0]);
            //Se vacía el objeto
            deskSign.clear();

            //Iniciar lector
            firmapdf.iniciarLector("Usuario: Eduardo", deskSign);
            
            if (deskSign.isSigned()){
                //Capturamos la fecha de la firma
                firmapdf.setLFecha(System.currentTimeMillis());
                firmapdf.setNombreCliente(deskSign.getName());

                //deskSign a XML
                archivoXML = new File(nombrePDF + ".xml");
                firmapdf.convertirAXML(deskSign, firmapdf.getLFecha(), firmapdf.getNombreCliente(), archivoXML);

                //comprimimos el XML
                String rutaZip = "C:\\" + nombrePDF + ".zip";
                firmapdf.comprimirXML(archivoXML,rutaZip);

                //Codificar
                CifrarDatos cifrar = new CifrarDatos();
                String hashZip = cifrar.recuperarHash(rutaZip);

                //Grabar imagen
                TratarPDF tratarPdf = new TratarPDF();
                firmapdf.setArchivoTemporal(File.createTempFile(nombrePDF + ".TEMP.pdf",null));
                tratarPdf.insertarImagen(deskSign,hashZip, args[0], firmapdf.getArchivoTemporal());

                //Firma digital
                String rutaFirmado = "C:\\" + nombrePDF + ".SIGNED.pdf";
                tratarPdf.firmaDigitalPDF(firmapdf.getArchivoTemporal(), rutaFirmado, ".\\keystore\\keystore.ks");
            } else {
                Logger.getLogger(FirmaPDF.class.getName()).log(Level.SEVERE, "Firma no capturada");
            } 
        } catch (DocumentException ex){
            Logger.getLogger(FirmaPDF.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ValidationException valEx){
            Logger.getLogger(FirmaPDF.class.getName()).log(Level.SEVERE, null, valEx);
        } catch (Exception eEx){
            Logger.getLogger(FirmaPDF.class.getName()).log(Level.SEVERE, null, eEx);
        } finally {
            if (archivoXML != null){
                archivoXML.deleteOnExit();
            }
            if (firmapdf.getArchivoTemporal() != null){
                firmapdf.getArchivoTemporal().deleteOnExit();
            }
        }
        System.exit(0);
    }

    /**
     * Método para lanzar el lector de ePadink
     * @param usuario
     * @param deskSign
     * @throws ValidationException 
     * 
     */
    private void iniciarLector (String usuario, DeskSign deskSign) throws ValidationException {
        /**
         * signNowEx(stringID, stringname, stringdesg, stringorg, string
         *   Addr, stringFooter, booleanshowOptions, integrisign.IdocInfoidinfo)
         */
       deskSign.signNowEx(usuario, "Designacion", "Organizacion", "Direccion", "Otra informacion", true, (IDocInfo)this);
    }

    /**
     * Crea un fichero XML con los datos obtenidos del objeto deskSign
     * @param deskSign
     * @param lfecha
     * @param nombre
     * @param archivoXML 
     */
    public void convertirAXML (DeskSign deskSign, long lfecha, String nombre, File archivoXML){
        FileOutputStream file = null;
         try { 
            //Creamos un elemento root 
            Element root = new Element("DeskSign");

            //Creamos un hijo para el root 
            Element datos = new Element("datos"); 
            Element titulo = new Element("titulo").setText("Datos de ePadink"); 

            PlantillaXML epadInk = new PlantillaXML("Aparato");
            epadInk.PlantillaXMLAparato(deskSign, lfecha);
            datos.addContent(titulo).addContent(epadInk);

            PlantillaXML cliente = new PlantillaXML ("cliente");
            cliente.PlantillaXMLCliente(nombre);
            datos.addContent(cliente);

            root.addContent(datos); 
            Document doc = new Document(root);//Creamos el documento

            //Vamos a almacenarlo en un fichero
            XMLOutputter out = new XMLOutputter(Format.getPrettyFormat()); 
            file = new FileOutputStream(archivoXML); 
            out.output(doc, file); 
        } catch (FileNotFoundException e) { 
            Logger.getLogger(FirmaPDF.class.getName()).log(Level.SEVERE, null, e);
        } catch (IOException ex) {
            Logger.getLogger(FirmaPDF.class.getName()).log(Level.SEVERE, null, ex);
        } catch (Exception e) {
            Logger.getLogger(FirmaPDF.class.getName()).log(Level.SEVERE, null, e);            
        } finally {
            try {
                file.flush(); 
                file.close();
            } catch (IOException ex) {
                Logger.getLogger(FirmaPDF.class.getName()).log(Level.SEVERE, null, ex);
            }
         }
    }

    /**
     * Método encargado de comprimir el fichero XML generado antes
     * @param archivoXML
     * @param rutaSalida 
     */
    public void comprimirXML (File archivoXML, String rutaSalida){
        FileInputStream in = null;
        try {
            in = new FileInputStream(archivoXML);
            FileOutputStream out = new FileOutputStream(rutaSalida);
            byte b[] = new byte[2048];
            ZipOutputStream zipOut = new ZipOutputStream(out);
            zipOut.setLevel(9);
            ZipEntry entry = new ZipEntry(archivoXML.getName());
            zipOut.putNextEntry(entry);
            int len = 0;
            while ((len = in.read(b)) != -1) {
                    zipOut.write(b, 0, len);
            }
            zipOut.closeEntry();
            zipOut.close();
        } catch (FileNotFoundException ex) {
            Logger.getLogger(FirmaPDF.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(FirmaPDF.class.getName()).log(Level.SEVERE, null, ex);
        } catch (Exception e) {
            Logger.getLogger(FirmaPDF.class.getName()).log(Level.SEVERE, null, e);
        } finally {
            try {
                in.close();
            } catch (IOException ex) {
                Logger.getLogger(FirmaPDF.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    private String recuperaNombreFichero (String ruta){
        String nombre = "";
        nombre = ruta.substring(ruta.lastIndexOf("\\")+1, ruta.lastIndexOf('.'));
        return nombre;
    }

    /**
     * @return byte
     */
    public byte getVersion() {
        return 1;
    }

    /**
     * @return String
     */
    public String getDocID() {
        return "";
    }

    /**
     * @param ig 
     */
    public void feedGrabber(integrisign.IGrabber ig) {
        //BUILD THE HASH INFORMATION OF THE DATA THAT NEEDS TO BOUND TO SIGNATURE OBJECT
        String str = "Nombre y Mensaje";
        ig.grabBytes(str.getBytes());
        ig.finishGrab();
    }

    /**
     * @param lfecha 
     */
    public void setLFecha (long lfecha){
        lFecha = lfecha;
    }

    /**
     * @return long
     */
    public long getLFecha (){
        return lFecha;
    }

    /**
     * @param nombreClient 
     */
    public void setNombreCliente (String nombreClient){
        nombreCliente = nombreClient;
    }

    /**
     * @return String
     */
    public String getNombreCliente (){
        return nombreCliente;
    }

    /**
     * @return the archivoTemporal
     */
    public File getArchivoTemporal() {
        return archivoTemporal;
    }

    /**
     * @param archivoTemporal the archivoTemporal to set
     */
    public void setArchivoTemporal(File archivoTemporal) {
        this.archivoTemporal = archivoTemporal;
    }
}